using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Drawing;
using System.Collections;
using System.Data;
using System.Text;
using Microsoft.PointOfService;
using System.Printing;
using System.Collections.Specialized;
using System.Management;

namespace Printing
{
    public class PrintDGV
    {
        private StringFormat StrFormat;  // Holds content of a TextBox Cell to write by DrawString
        private StringFormat StrFormatComboBox; // Holds content of a Boolean Cell to write by DrawImage
        private Button CellButton;       // Holds the Contents of Button Cell
        private CheckBox CellCheckBox;   // Holds the Contents of CheckBox Cell 
        private ComboBox CellComboBox;   // Holds the Contents of ComboBox Cell

        private int TotalWidth;          // Summation of Columns widths
        private int RowPos;              // Position of currently printing row 
        private bool NewPage;            // Indicates if a new page reached
        private int PageNo;              // Number of pages to print
        private List<float> ColumnLefts;  // Left Coordinate of Columns
        private List<float> ColumnWidths; // Width of Columns
        private ArrayList ColumnTypes = new ArrayList();  // DataType of Columns
        private int CellHeight;          // Height of DataGrid Cell
        private int RowsPerPage;         // Number of Rows per Page
        private System.Drawing.Printing.PrintDocument printDoc =
                       new System.Drawing.Printing.PrintDocument();  // PrintDocumnet Object used for printing

        private string PrintTitle = "";  // Header of pages
        private DataGridView dgv;        // Holds DataGridView Object to print its contents
        public List<string> SelectedColumns = new List<string>();   // The Columns Selected by user to print.
        //private List<string> AvailableColumns = new List<string>();  // All Columns avaiable in DataGrid 
        private bool PrintAllRows = true;   // True = print all rows,  False = print selected rows    
        private bool FitToPageWidth = true; // True = Fits selected columns to page width ,  False = Print columns as showed    
        private int HeaderHeight = 0;
        private PrintPreviewDialog ppvw;
        private Font headerFont;
        public List<PrintText> headerRegionTexts;
        public List<PrintText> footerRegionTexts;
        private Font normalFont;
        private Font footerFont;
        private PosPrinter oPrinter;

        public List<PrintText> sumRegionTexts;
        private bool ColProductIsName;

        public PrintDGV(DataGridView dgv1,
            List<string> printColumns, List<float> columnsWidth, string printTitle, string printerName, bool colProductIsName = false)
        {
            try 
	        {	
                // Getting DataGridView object to print
                dgv = dgv1;

                PrintTitle = printTitle;
                PrintAllRows = true;
                FitToPageWidth = true;
                SelectedColumns = printColumns;
                ColumnWidths = columnsWidth;
                ColumnLefts = new List<float>();
                ColProductIsName = colProductIsName;

                RowsPerPage = 0;

                ppvw = new PrintPreviewDialog();
                ppvw.Document = printDoc;

                if (!string.IsNullOrWhiteSpace(printerName))
                {
                    printDoc.PrinterSettings.PrinterName = printerName;
                }
                // Showing the Print Preview Page
                printDoc.BeginPrint +=new System.Drawing.Printing.PrintEventHandler(PrintDoc_BeginPrint);
                printDoc.PrintPage +=new System.Drawing.Printing.PrintPageEventHandler(PrintDoc_PrintPage);
                printDoc.EndPrint += new System.Drawing.Printing.PrintEventHandler(printDoc_EndPrint);

                headerFont = new Font("Arial", 20, FontStyle.Bold);
                normalFont = new Font("Arial", 8);
                footerFont = new Font("Arial", 10, FontStyle.Bold);

                //if (ppvw.ShowDialog() != DialogResult.OK)
                //{
                    //printDoc.BeginPrint -= new System.Drawing.Printing.PrintEventHandler(PrintDoc_BeginPrint);
                    //printDoc.PrintPage -= new System.Drawing.Printing.PrintPageEventHandler(PrintDoc_PrintPage);
                    //return;
                //}

                // Printing the Documnet
                //printDoc.Print();
                //printDoc.BeginPrint -= new System.Drawing.Printing.PrintEventHandler(PrintDoc_BeginPrint);
                //printDoc.PrintPage -= new System.Drawing.Printing.PrintPageEventHandler(PrintDoc_PrintPage);

                //CreatePosPrinter();
	        }
	        catch (Exception ex)
	        {
                MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);        		
	        }
            finally
            {

            }
        }

        private void printDoc_EndPrint(object sender, System.Drawing.Printing.PrintEventArgs e)
        {
            //String pServer = "\\\\" + Environment.MachineName;
            //String printerName = "EPSON TM-T81 Receipt";
            //// Create objects to represent the server, queue, and print job.
            //PrintServer hostingServer = new PrintServer(pServer, PrintSystemDesiredAccess.AdministrateServer);
            //PrintQueue hostingQueue = new PrintQueue(hostingServer, printerName, PrintSystemDesiredAccess.AdministratePrinter);

            //List<int> printJobID = new List<int>();
            //string searchQuery = "SELECT * FROM Win32_PrintJob";

            ///*searchQuery can also be mentioned with where Attribute,
            //    but this is not working in Windows 2000 / ME / 98 machines 
            //    and throws Invalid query error*/
            //ManagementObjectSearcher searchPrintJobs =
            //          new ManagementObjectSearcher(searchQuery);
            //ManagementObjectCollection prntJobCollection = searchPrintJobs.Get();
            //foreach (ManagementObject prntJob in prntJobCollection)
            //{
            //    System.String jobName = prntJob.Properties["Name"].Value.ToString();

            //    //Job name would be of the format [Printer name], [Job ID]

            //    char[] splitArr = new char[1];
            //    splitArr[0] = Convert.ToChar(",");
            //    string prnterName = jobName.Split(splitArr)[0];
            //    int prntJobID = Convert.ToInt32(jobName.Split(splitArr)[1]);
            //    string documentName = prntJob.Properties["Document"].Value.ToString();
            //    if (String.Compare(prnterName, printerName, true) == 0)
            //    {
            //        printJobID.Add(prntJobID);
            //    }
            //}

            //if (printJobID.Count > 0)
            //{
            //    PrintSystemJobInfo theJob = hostingQueue.GetJob(printJobID[0]);
            //    if (theJob.IsPaperOut)
            //    {
            //        MessageBox.Show("Khong du giay");
            //    }
            //}
        }

        private void CreatePosPrinter()
        {
            PosExplorer myExplorer = new PosExplorer();
            try
            {
                DeviceInfo oDevicePrinter = myExplorer.GetDevice(DeviceType.PosPrinter, "PosPrinter");
                if (oDevicePrinter != null)
                {
                    oPrinter = (PosPrinter)myExplorer.CreateInstance(oDevicePrinter);

                    if (oPrinter != null)
                    {
                        oPrinter.Open();
                        oPrinter.Claim(1000);
                        oPrinter.DeviceEnabled = true;
                        oPrinter.ErrorEvent += new DeviceErrorEventHandler(oPrinter_ErrorEvent);
                    }
                }
            }
            catch (Exception exPrinter)
            {
                //MessageBox.Show(exPrinter.ToString(), "Warning");
            }
        }

        private void oPrinter_ErrorEvent(object sender, DeviceErrorEventArgs e)
        {
            string test = "";
        }

        public void Release()
        {
            //if (oPrinter != null)
            //{
            //    try
            //    {
            //        //Cancel the device
            //        oPrinter.DeviceEnabled = false;

            //        //Release the device exclusive control right.
            //        oPrinter.Release();

            //    }
            //    catch (PosControlException)
            //    {
            //    }
            //    finally
            //    {
            //        //Finish using the device.
            //        oPrinter.Close();
            //    }
            //}
        }

        private void PrintDoc_BeginPrint(object sender, 
                    System.Drawing.Printing.PrintEventArgs e) 
        {
            try
	        {
                // Formatting the Content of Text Cell to print
                StrFormat = new StringFormat();
                StrFormat.Alignment = StringAlignment.Near;
                StrFormat.LineAlignment = StringAlignment.Center;
                StrFormat.Trimming = StringTrimming.EllipsisCharacter;

                // Formatting the Content of Combo Cells to print
                StrFormatComboBox = new StringFormat();
                StrFormatComboBox.LineAlignment = StringAlignment.Center;
                StrFormatComboBox.FormatFlags = StringFormatFlags.NoWrap;
                StrFormatComboBox.Trimming = StringTrimming.EllipsisCharacter;

                //ColumnLefts.Clear();
                //ColumnWidths.Clear();
                //ColumnTypes.Clear();
                CellHeight = 0;
                RowsPerPage = 0;

                // For various column types
                CellButton = new Button();
                CellCheckBox = new CheckBox();
                CellComboBox = new ComboBox();

                // Calculating Total Widths
                TotalWidth = 0;
                foreach (DataGridViewColumn GridCol in dgv.Columns)
                {
                    if (!GridCol.Visible) continue;
                    if (!SelectedColumns.Contains(GridCol.Name)) continue;
                    TotalWidth += GridCol.Width;
                }
                PageNo = 1;
                NewPage = true;
                RowPos = 0;        		
	        }
	        catch (Exception ex)
	        {
                MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);        		
	        }
        }

        private void PrintDoc_PrintPage(object sender, 
                    System.Drawing.Printing.PrintPageEventArgs e) 
        {
            float tmpWidth;
            float tmpTop = e.PageBounds.Top;
            float tmpLeft = e.PageBounds.Left;
            float leftMargin = e.PageBounds.Left;
            float topMargin = e.PageBounds.Top;
            float rightMargin = e.PageBounds.Right;
            float pageWidth = e.PageBounds.Width;
            //float tmpTop = 0;
            //float tmpLeft = 0;
            //float leftMargin = 0;
            //float topMargin = 0;
            float height;
            string tmpText;
            int i;

            try 
	        {	        
                // Before starting first page, it saves Width & Height of Headers and CoulmnType
                if (PageNo == 1) 
                {
                    i = 0;
                    foreach (DataGridViewColumn GridCol in dgv.Columns)
                    {
                        if (!GridCol.Visible) continue;
                        // Skip if the current column not selected
                        if (!SelectedColumns.Contains(GridCol.Name)) continue;

                        // Detemining whether the columns are fitted to page or not.
                        //if (FitToPageWidth) 
                        //    tmpWidth = (int)(Math.Floor((double)((double)GridCol.Width / 
                        //               (double)TotalWidth * (double)TotalWidth * 
                        //               ((double)e.PageBounds.Width / (double)TotalWidth))));
                        //else
                        //    tmpWidth = GridCol.Width;
                        tmpWidth = ColumnWidths[i];

                        HeaderHeight = (int)(e.Graphics.MeasureString(GridCol.HeaderText,
                                    GridCol.InheritedStyle.Font, (int)tmpWidth).Height) + 11;
                        
                        // Save width & height of headres and ColumnType
                        ColumnLefts.Add(tmpLeft);
                        //ColumnWidths.Add(tmpWidth);
                        ColumnTypes.Add(GridCol.GetType());
                        tmpLeft += tmpWidth;
                        i++;
                    }
                }

                // Printing Current Page, Row by Row
                while (RowPos <= dgv.Rows.Count - 1)
                {
                    DataGridViewRow GridRow = dgv.Rows[RowPos];
                    if (GridRow.IsNewRow || (!PrintAllRows && !GridRow.Selected))
                    {
                        RowPos++;
                        continue;
                    }

                    DataGridViewCell productCell = GridRow.Cells["colProduct"];
                    if (ColProductIsName)
                    {
                        if(string.IsNullOrWhiteSpace(productCell.Value.ToString())) 
                        {
                            RowPos++;
                            continue;
                        }
                    }
                    else
                    {
                        if (!(Convert.ToInt32(productCell.Value) > 0))
                        {
                            RowPos++;
                            continue;
                        }
                    }

                    CellHeight = GridRow.Height;

                    if (tmpTop + CellHeight >= e.PageBounds.Height + e.PageBounds.Top)
                    {
                        DrawFooter(e, RowsPerPage);
                        NewPage = true;
                        PageNo++;
                        e.HasMorePages = true;
                        return;
                    }
                    else
                    {
                        if (NewPage)
                        {
                            // Draw Header
                            tmpTop += e.PageBounds.Top;
                            //e.Graphics.DrawString(PrintTitle, new Font(dgv.Font, FontStyle.Bold), 
                            //        Brushes.Black, 
                            //        e.PageBounds.Width / 2, 
                            //        e.PageBounds.Top - e.Graphics.MeasureString(PrintTitle, new Font(dgv.Font, FontStyle.Bold), e.PageBounds.Width).Height - 13);

                            //height = e.Graphics.MeasureString(PrintTitle, headerFont).Height;
                            //StringFormat sf = new StringFormat();
                            //sf.Alignment = StringAlignment.Center;
                            //e.Graphics.DrawString(PrintTitle, headerFont,
                                    //Brushes.Black,
                                    //new RectangleF(leftMargin, topMargin, e.PageBounds.Width, height), sf);
                            // tmpTop += height;
                            // Print table and time
                            foreach (PrintText headerText in headerRegionTexts)
                            {
                                height = e.Graphics.MeasureString(headerText.PText, headerText.PFont).Height;
                                e.Graphics.DrawString(headerText.PText, headerText.PFont,
                                       Brushes.Black, new RectangleF(leftMargin, tmpTop, pageWidth, height), headerText.Paligntment);
                                tmpTop += height + 5;
                                //tmpTop += height;
                            }

                            //tmpTop += 10; //space between header and table
                            // Draw Columns header                        
                            i = 0;
                            foreach (DataGridViewColumn GridCol in dgv.Columns)
                            {
                                if (!GridCol.Visible) continue;
                                if (!SelectedColumns.Contains(GridCol.Name)) continue;

                                e.Graphics.FillRectangle(new SolidBrush(Color.White), 
                                    new RectangleF((int) ColumnLefts[i], tmpTop,
                                    (int)ColumnWidths[i], HeaderHeight));

                                e.Graphics.DrawRectangle(Pens.Black, 
                                    ColumnLefts[i], tmpTop,
                                    ColumnWidths[i], HeaderHeight);

                                if (GridCol.DefaultCellStyle.Alignment == DataGridViewContentAlignment.MiddleRight)
                                {
                                    StrFormat.Alignment = StringAlignment.Far;
                                }
                                else
                                {
                                    StrFormat.Alignment = StringAlignment.Near;
                                }

                                e.Graphics.DrawString(GridCol.HeaderText, normalFont, 
                                    new SolidBrush(Color.Black),
                                    new RectangleF((int)ColumnLefts[i], tmpTop, 
                                    (int)ColumnWidths[i], HeaderHeight), StrFormat);
                                i++;
                            }
                            NewPage = false;
                            tmpTop += HeaderHeight;
                        }

                        // Draw Columns Contents
                        i = 0;
                        foreach (DataGridViewCell Cel in GridRow.Cells)
                        {
                            if (!Cel.OwningColumn.Visible) continue;
                            if (!SelectedColumns.Contains(Cel.OwningColumn.Name))
                                continue;

                            // For the TextBox Column
                            if (Cel.OwningColumn.DefaultCellStyle.Alignment == DataGridViewContentAlignment.MiddleRight)
                            {
                                StrFormat.Alignment = StringAlignment.Far;
                            }
                            else
                            {
                                StrFormat.Alignment = StringAlignment.Near;
                            }
                            string cellValue = Cel.EditedFormattedValue.ToString();
                            if (Cel.ColumnIndex == dgv.Columns["colWarrantyTime"].Index)
                            {
                                if (string.IsNullOrEmpty(cellValue))
                                {
                                    cellValue = "0";
                                }
                                cellValue = cellValue + "T";
                            }
                            e.Graphics.DrawString(cellValue, normalFont,
                                    new SolidBrush(Color.Black),
                                    new RectangleF((int)ColumnLefts[i], (float)tmpTop,
                                    (int)ColumnWidths[i], (float)CellHeight), StrFormat);

                            // Drawing Cells Borders 
                            e.Graphics.DrawRectangle(Pens.Black, ColumnLefts[i], tmpTop, ColumnWidths[i], CellHeight);

                            i++;

                        }
                        tmpTop += CellHeight;
                    }

                    RowPos++;
                    // For the first page it calculates Rows per Page
                    if (PageNo == 1) RowsPerPage++;
                }
               
                // Write sum texts
                float left = ColumnLefts[ColumnLefts.Count - 1] + ColumnWidths[ColumnWidths.Count - 1] - 20;
                tmpTop += 5;

                foreach (PrintText sumText in sumRegionTexts)
                {
                    height = e.Graphics.MeasureString(sumText.PText, sumText.PFont).Height;
                    e.Graphics.DrawString(sumText.PText, sumText.PFont,
                                      Brushes.Black, left, tmpTop, sumText.Paligntment);

                    //e.Graphics.DrawString(footerText.PText, footerText.PFont, Brushes.Black, 
                    //left, tmpTop, sf1);

                    tmpTop += height;
                }

                // Write footer texts
                left = 0;
                tmpTop += 5;
                foreach (PrintText footerText in footerRegionTexts)
                {
                    height = e.Graphics.MeasureString(footerText.PText, footerText.PFont).Height;
                    //e.Graphics.DrawString(footerText.PText, footerText.PFont,
                    //                  Brushes.Black, leftMargin, tmpTop, footerText.Paligntment);

                    e.Graphics.DrawString(footerText.PText, footerText.PFont,
                                       Brushes.Black, new RectangleF(leftMargin, tmpTop, pageWidth, height), footerText.Paligntment);
                    
                    tmpTop += height;
                }

                if (RowsPerPage == 0) return;

                // Write Footer (Page Number)
                //DrawFooter(e, RowsPerPage);//TODO: Check the footer

                e.HasMorePages = false;
	        }
	        catch (Exception ex)
	        {
                MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);        		
	        }
        }

        private void DrawFooter(System.Drawing.Printing.PrintPageEventArgs e, 
                    int RowsPerPage)
        {
            double cnt = 0; 

            // Detemining rows number to print
            if (PrintAllRows)
            {
                if (dgv.Rows[dgv.Rows.Count - 1].IsNewRow) 
                    cnt = dgv.Rows.Count - 2; // When the DataGridView doesn't allow adding rows
                else
                    cnt = dgv.Rows.Count - 1; // When the DataGridView allows adding rows
            }
            else
                cnt = dgv.SelectedRows.Count;

            // Writing the Page Number on the Bottom of Page
            string PageNum = PageNo.ToString() + " of " + 
                Math.Ceiling((double)(cnt / RowsPerPage)).ToString();

            e.Graphics.DrawString(PageNum, dgv.Font, Brushes.Black, 
                e.PageBounds.Left + (e.PageBounds.Width - 
                e.Graphics.MeasureString(PageNum, dgv.Font, 
                e.PageBounds.Width).Width) / 2, e.PageBounds.Top + 
                e.PageBounds.Height + 31);
        }

        public void Print()
        {
            // Printing the Documnet
            printDoc.Print();
            //ppvw.ShowDialog();
        }
    }
}
